Примитивны синхронизации, потокобезопасные коллекции

lock → Monitor

lock если объект монитора уже закрыт просто блокирует поток

lock(obj){
	...
}

Эта конструкция превращается в правую конструкцию

try{
	var lockTaken = false;
	Monitor.Enter(obj, ref lockTaken);
	...
}
finally
{
	if(lockTaken)
	{
		Monitor.Exit(obj)
	}
}

MethodImplOptions.Synchronized

[MethodImpl(MethodImplOptions.Synchronized)]
public void CriticalMethod()
{
	...
}
  • внутри lock нельзя использовать ключевое слово await, код не скомпилируется, но можно самому развернуть в Monitor и все будет норм, но теперь эксепшн. Проблема в том, что код после await может быть продолжен не тем потоком, который его начал. Тогда lock будет сниматься не тем потоком который его установил, что не правильно
  • Объектом синхронизации должен быть ссылочный тип из-за того что во время упаковки происходит создание нового объекта
  • лок может быть вложеным с одним и тем же типом блокировки, так как блокировка это инт, её можно накладывать несколько раз

SpinLock

Он требуется чтобы пореже переключать контекст, т.к. в случае обычного лока, контекст переключается постоянно

private SpinLock obj = new SpinLock();

public void Method(){
	var lockTaken = false;
	try
	{
		obj.Enter(ref lockTaken);
	}
	finally
	{
		if(lockTaken){
			obj.Exit(false);
		}
	}
}

Эта штука не перключает сразу контекст а запускает в цикле метод SpinOnce, в нем есть три варинта

SpinLock это структура, поэтому его нужно передавать строко по ref, иначе он будет не иметь смысла

Untitled 2.png
Контекст потока — это всё состояние, необходимое процессору, чтобы приостановить выполнение потока и потом продолжить его с того же места.

Он включает:

Компонент Что это такое
📌 Регистр EIP / RIP Адрес следующей инструкции (точка исполнения)
📌 Стек ESP / RSP Указатель на вершину стека
📦 Регистры общего назначения eax, ebx, rcx, rdx и др.
🧾 Флаги процессора Режимы исполнения, флаги прерываний
🗂️ Состояние SIMD/FPU (если нужно) Для векторных операций, xmm, ymm
📎 Локальные переменные Хранятся в стеке (или регистрах)
🧩 Информация ОС Приоритет, дескрипторы, права, область памяти

Процесс переключения контекста, это когда ОС сохраняет текущее состояние контекста и загружает в процессор другой поток с другим контекстом.

⚙ ReaderWriderLockSlim

Untitled 1.png

Данная штука позволяет область кода сделать такой, чтобы все кто хотели могли читать, но писать мог только один и при этом, если кто то начинает писать, то все ребята на чтение заканчивают читать а все попытке прочесть становятся в очередь пока не закончиться запись

⚙ SemaphoreSlim

  • Пример использования, допустим хотим распараллелить число запросов куда-то, но не хотим чтобы их было слишком много

Существуют примитивы с приставкой Slim и без, отличие в том, что без такого суффикса примитивы появились раньше, когда дотнет был только под винду и они отличаются тем что опускали примитивы на уровень ОС, в то время как Slim разбираются на уровне приложения

Есть два вида потоко безопасных коллекций:

  1. Cuncurent регулируют потоки на добавление и удаление
  2. Immutable регулируют потоки тем, что на каждое действие создают новый список
  • CuncurrentBag

  • CuncurrentStack

  • CuncurrentQueue

  • ConcurrentDictionary<TKey, TValue>
    Добавляя новый элемент, поток добавляет каждый в свою коллекцию, а если читать, то сначала из своего, а потом блокировать другой поток и читать из чужого

  • ImmutableList

  • ImmutableArray

  • ImmutableHashSet

  • ImmutableQueue

  • ImmutableStack